using System;
using Microsoft.SPOT;

namespace Gadgeteer.Modules.Community.XBee
{
    /// <summary>
    /// Base class for all API Messages, handles parsing messages
    /// </summary>
    public abstract class BaseAPIMessage
    {
        /// <summary>
        /// length of message in bytes, message bytes 1 and 2
        /// </summary>
        public ushort MessageByteCount { get; set; }
        /// <summary>
        /// The type of message
        /// </summary>
        public ushort FrameId { get; set; }
        /// <summary>
        /// Checksum of message
        /// </summary>
        public ushort CheckSum { get; set; }

        /// <summary>
        /// parses an API message
        /// </summary>
        /// <param name="message">API message bytes</param>
        public void Parse(byte[] message)
        {
            if (message.Length < 6)
            {
                throw new XBeeClientException("The message needs to be at least 6 bytes long to be valid API message");
            }

            if ((ushort)message[0] != (ushort)APIMessageEnum.StartDelimiter)
            {
                throw new XBeeClientException("The message started with something other than start delimiter");
            }

            ParseMessageByteCount(message[2], message[1]);

            ValidateMessageType(message[3]);

            ParseFrameId(message[4]);

            ParseMessageBody(message);

            ParseCheckSum(message[message.Length - 1]);

            ValidateCheckSum();
        }

        private void ParseMessageByteCount(byte lsb, byte msb)
        {
            MessageByteCount = (ushort)((msb << 8) + lsb);
        }

        private void ParseFrameId(byte frameId)
        {
            FrameId = (ushort)frameId;
        }

        private void ParseCheckSum(byte checksum)
        {
            CheckSum = (ushort)checksum;
        }

        private void ValidateCheckSum()
        {
            // TODO
        }

        private void ValidateMessageType(byte messageType)
        {
            if ((ushort)messageType != MessageType)
            {
                throw new XBeeClientException("Message type byte did not match expected message type value. was " + messageType.ToString() + ", should be " + MessageType.ToString());
            }
        }

        /// <summary>
        /// abstract method for MessageType
        /// </summary>
        /// <returns>string representing the message type</returns>
        abstract protected string MessageTypeToString();

        /// <summary>
        /// abstract Getter for MessageType
        /// </summary>
        abstract protected ushort MessageType { get; }

        /// <summary>
        /// Virtual method for parsing the message body
        /// </summary>
        /// <param name="message">API message</param>
        public virtual void ParseMessageBody(byte[] message)
        {

        }

        /// <summary>
        /// MessageBody
        /// </summary>
        /// <returns>body of the message if there is one</returns>
        public virtual string MessageBodyToString()
        {
            return String.Empty;
        }

        /// <summary>
        /// Override of ToString, formats the API message in readabile format
        /// </summary>
        /// <returns>formated API message</returns>
        public override string ToString()
        {
            string result = String.Empty;

            try
            {
                string messageBody = MessageBodyToString();
                string messageBodyMessage = messageBody == String.Empty ? String.Empty : "Message Body: \n"
                    + MessageBodyToString() + "\n";

                result = MessageTypeToString() + "\n"
                    + "Message Byte Count: " + MessageByteCount.ToString() + "\n"
                    + "Message Type: " + MessageTypeToString() + "\n"
                    + "Frame ID: " + FrameId.ToString() + "\n"
                    + messageBodyMessage
                    + "Checksum: " + CheckSum.ToString() + "\n";
            }
            catch (Exception)
            {
                throw;
            }

            return result;
        }
    }
}
